package com.javasm.adminapi.common.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.net.UnknownHostException;

@Configuration
@EnableCaching
public class RedisConfig {

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        //1、创建RedisTemplate实例，通过泛型来规定key的类型必须是String，Value的类型是任意对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //2、设置连接的工厂，让Template知道如何连接Redis服务器
        template.setConnectionFactory(redisConnectionFactory);
        //3、创建JSON序列化器，用于将Java对象和Json互相转换
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
                new Jackson2JsonRedisSerializer<>(Object.class);
        //4、配置Jackson的ObjectMapper，json处理的核心工具
        ObjectMapper objectMapper = new ObjectMapper();
        //5、设置所有字段课件，包括自由字段，这样才能序列化对象的所有属性
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //6、启用自动类型识别，反序列化的时候，能正常还原对象类型
        objectMapper.activateDefaultTyping(
                LaissezFaireSubTypeValidator.instance,//类型验证器
                ObjectMapper.DefaultTyping.NON_FINAL//对非final类，记录类型信息
        );
        //7、将配置好的ObjectMapper注入Json序列化器中
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        //8、创建字符串序列化器，用于处理key的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //9、设置普通的key的序列化方式，字符串格式
        template.setKeySerializer(stringRedisSerializer);
        //10、设置Hash类型的key的序列化放方式  字符串（决定，Hash类型的key，都是String）
        template.setHashKeySerializer(stringRedisSerializer);
        //11、设置普通的value序列化方式，JSON格式
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //12、设置 Hash类型的value的序列化方式
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        //13、初始化配置，确保所有的设置生效
        template.afterPropertiesSet();
        //14、返回配置好的RedisTemplate对象
        return template;
    }
}
